/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import java.lang.reflect.InvocationTargetException;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.PerforceSynchronizer;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.core.resources.RemoteFolder;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.core.internal.resources.ProjectDescription;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class CheckoutAction extends PerforceAction {
  //----------------------------------------------------------------------------
  // -- Public Methods

  @Override
  public void run(IAction action) {
    run(new WorkspaceModifyOperation() {
      /**
       * Return whether or not the specifed location is a prefix of the root.
       */
      private boolean isPrefixOfRoot(IPath locationPath) {
        return Platform.getLocation().isPrefixOf(locationPath);
      }

      @SuppressWarnings("unused")
      // InterruptedException
      @Override
      public void execute(IProgressMonitor monitor) throws InvocationTargetException,
          InterruptedException {
        try {
          PerforceSynchronizer.getInstance().beginOperation(monitor);

          IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
          RemoteFolder[] folders = getSelectedRemoteFolders();

          monitor.beginTask("", folders.length * 1000);
          for (int i = 0; i < folders.length; i++) {
            RemoteFolder folder = folders[i];
            final String projectName = getProjectName(folder.getName());
            if (projectName == null) {
              return;
            }

            IProject project = root.getProject(projectName);
            if (project.exists()) {
              showProjectExistsError(projectName);
            } else {
              monitor.setTaskName("Checking out '" + projectName + "' from Perforce...");

              folder.sync("#head", Policy.subMonitorFor(monitor, 300));

              IProjectDescription projectDescription = new ProjectDescription();
              projectDescription.setName(project.getName());
              IPath locationPath = folder.getLocation();
              if (isPrefixOfRoot(locationPath))
                projectDescription.setLocation(null);
              else
                projectDescription.setLocation(locationPath);

              project.create(projectDescription, Policy.subMonitorFor(monitor, 100));

              if (!project.isOpen()) {
                project.open(Policy.subMonitorFor(monitor, 100));
              } else {
                project.refreshLocal(IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, 100));
              }

              PerforceCorePlugin.getServerManager().setSharing(project, folder.getServer(),
                  Policy.subMonitorFor(monitor, 100));

              P4TeamProvider provider = (P4TeamProvider) RepositoryProvider.getProvider(project);
              provider.refreshState(new IResource[] {project}, IResource.DEPTH_INFINITE, Policy
                  .subMonitorFor(monitor, 400));
            }
          }
        } catch (TeamException e) {
          throw new InvocationTargetException(e);
        } catch (CoreException e) {
          throw new InvocationTargetException(e);
        } finally {
          try {
            PerforceSynchronizer.getInstance().endOperation(monitor);
          } catch (PerforceException e) {
            PerforceUIPlugin.log(e.getStatus());
          }
          monitor.done();
        }
      }

      private void showProjectExistsError(final String projectName) {
        getShell().getDisplay().syncExec(new Runnable() {
          public void run() {
            ErrorDialog.openError(getShell(), "Error",
                "The workspace already contains the project " + projectName, new Status(
                    Status.ERROR, PerforceUIPlugin.ID, Status.ERROR, "", null));
          }
        });
      }
    }, PROGRESS_DIALOG, false);
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  @SuppressWarnings("unused")
  // PerforceException
  @Override
  protected boolean isEnabled() throws PerforceException {
    RemoteFolder[] folders = getSelectedRemoteFolders();
    return folders.length > 0;
  }

  /**
   * Returns the name under which the given project should be created.
   * 
   * @param projectName the name of the project.
   * @return the name under which the project will be created or null to abort.
   */
  protected String getProjectName(String projectName) {
    return projectName;
  }
}
